{% extends "base.html" %}
{% load static %}
{% load i18n %}

{% block title %}{{ title }} | {{ block.super }}{% endblock %}
{% block extra_css %}
<link rel="stylesheet" href="{% static 'daterangepicker/daterangepicker.css' %}">
{% endblock %}
{% block page_title %}{{ title }}{% endblock %}
{% block page_subtitle %}{{ subtitle }}{% endblock %}

{% block breadcrumb %}
<div class="box-tools">
  <div class="btn-group margin-r-5" style="display: none;">
    <button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
      {% for option in metadata.period_options %}
      {% if option.selected %}{{ option.label }}{% endif %}
      {% endfor %}
      <span class="caret"></span>
    </button>
    <ul class="dropdown-menu" role="menu">
      {% for option in metadata.period_options %}
      <li class="{% if option.selected %}active{% endif %}"><a href="#"
          data-value="{{ option.value }}">{{ option.label }}</a></li>
      {% endfor %}
    </ul>
  </div>
  <div class="btn-group margin-r-5" id="reportrange">
    <button type="button" class="btn btn-default btn-sm">
      <i class="fa fa-calendar"></i>&nbsp;
      <span></span>
    </button>
  </div>
  <div class="btn-group">
    <button type="button" class="btn btn-primary btn-sm" id="export-report"><i class="fa fa-download"></i>
      {% trans '导出报告' %}</button>
  </div>
</div>
{% endblock %}

{% block content %}
<div class="row">
  <div class="col-lg-4 col-md-4 col-sm-6">
    <div class="info-box">
      <span class="info-box-icon bg-aqua"><i class="fa fa-building"></i></span>
      <div class="info-box-content">
        <span class="info-box-text">{% trans "所有变更" %}</span>
        <span class="info-box-number" id="rack-kpis-total"></span>
        <span class="info-box-text" id="rack-kpis-total-desc" style="font-size:12px;color:#666;"></span>
      </div>
    </div>
  </div>
  <div class="col-lg-4 col-md-4 col-sm-6">
    <div class="info-box">
      <span class="info-box-icon bg-green"><i class="fa fa-puzzle-piece"></i></span>
      <div class="info-box-content">
        <span class="info-box-text">{% trans "新增" %}</span>
        <span class="info-box-number" id="rack-kpis-allocate"></span>
        <span class="info-box-text" id="rack-kpis-allocate-desc" style="font-size:12px;color:#666;"></span>
      </div>
    </div>
  </div>
  <div class="col-lg-4 col-md-4 col-sm-6">
    <div class="info-box">
      <span class="info-box-icon bg-red"><i class="fa fa-recycle"></i></span>
      <div class="info-box-content">
        <span class="info-box-text">{% trans "减少" %}</span>
        <span class="info-box-number" id="rack-kpis-deallocate"></span>
        <span class="info-box-text" id="rack-kpis-deallocate-desc" style="font-size:12px;color:#666;"></span>
      </div>
    </div>
  </div>
</div>

<div class="row">
  <div class="col-md-8">
    <div class="box box-solid">
      <div class="box-header with-border">
        <h3 class="box-title">{% trans "机柜变更分析" %}
          <small style="margin-left:1px;"><a tabindex="0" class="text-muted" data-toggle="popover" data-trigger="focus"
              data-placement="bottom" data-content="{% trans '展示所选时间范围内机柜分配/释放趋势。' %}"><i
                class="fa fa-info-circle"></i></a></small>
        </h3>
        <div class="box-tools pull-right" id="aggregation-buttons">
          {% for option in metadata.aggregation_options %}
          <button class="btn btn-default btn-xs agg-btn{%if option.selected %} active{% endif %}"
            data-agg="{{ option.value }}">{{ option.label }}</button>
          {% endfor %}
        </div>
      </div>
      <div class="box-body">
        <div id="rack-trend-chart" style="height: 400px;"></div>
      </div>
    </div>
  </div>
  <div class="col-md-4">
    <div class="box box-solid">
      <div class="box-header with-border">
        <h3 class="box-title">{% trans "机柜状态分布" %}
          <small style="margin-left: 1px;">
            <a tabindex="0" class="text-muted" data-toggle="popover" data-trigger="focus" data-placement="bottom"
              data-content="{% trans '展示所选时间范围内机柜状态分布情况(不含未指定状态的机柜)' %}"><i class="fa fa-info-circle"></i></a>
          </small>
        </h3>
      </div>
      <div class="box-body">
        <div id="rack-status-chart" style="height: 400px;"></div>
      </div>
    </div>
  </div>
</div>

<div class="row">
  <div class="col-md-5">
    <div class="box box-solid">
      <div class="box-header with-border">
        <h3 class="box-title">{% trans "机柜房间表现" %}
          <small style="margin-left:1px;"><a tabindex="0" class="text-muted" data-toggle="popover" data-trigger="focus"
              data-placement="bottom" data-content="{% trans '按房间汇总可上架机柜数量，并按状态堆叠展示。' %}"><i
                class="fa fa-info-circle"></i></a></small>
        </h3>
      </div>
      <div class="box-body">
        <div id="room-stackedbar-chart" style="height: 380px;"></div>
      </div>
    </div>
  </div>
  <div class="col-md-7">
    <div class="box box-solid">
      <div class="box-header with-border">
        <h3 class="box-title">{% trans "客户机柜表现" %}
          <small style="margin-left:1px;"><a tabindex="0" class="text-muted" data-toggle="popover" data-trigger="focus"
              data-placement="bottom" data-content="{% trans '按客户统计：总机柜数、期间分配/释放、平均使用率。默认按新增(分配)倒序排序。' %}"><i
                class="fa fa-info-circle"></i></a></small>
        </h3>
        <div class="box-tools pull-right" id="tenant-sort-buttons">
          <button class="btn btn-primary btn-xs tenant-sort-btn active" data-key="allocated">{% trans '新增' %}</button>
          <button class="btn btn-default btn-xs tenant-sort-btn" data-key="deallocated">{% trans '减少' %}</button>
          <button class="btn btn-default btn-xs tenant-sort-btn" data-key="avg_utilization">{% trans '使用率' %}</button>
          <button class="btn btn-default btn-xs tenant-sort-btn" data-key="free_rate">{% trans '空闲率' %}</button>
        </div>
      </div>
      <div class="box-body">
        <div class="table-responsive">
          <table class="table table-bordered" id="tenant-stats-table">
            <thead>
              <tr class="active">
                <th>{% trans '客户' %}</th>
                <th class="text-right">{% trans '总机柜数' %}</th>
                <th class="text-right">{% trans '新增' %}</th>
                <th class="text-right">{% trans '减少' %}</th>
                <th class="text-right">{% trans '使用率(%)' %}
                  <a tabindex="0" class="text-muted" data-toggle="popover" data-trigger="focus" data-placement="top"
                    data-content="{% trans '平均使用率=各机柜(已用U/机柜U高)的加权平均，已用U=设备U(优先设备高度，其次型号高度)。' %}"><i
                      class="fa fa-info-circle"></i></a>
                </th>
                <th class="text-right">{% trans '空闲率(%)' %}
                  <a tabindex="0" class="text-muted" data-toggle="popover" data-trigger="focus" data-placement="top"
                    data-content="{% trans '空闲率=无上架/迁移设备的机柜数 / 总机柜数。' %}"><i class="fa fa-info-circle"></i></a>
                </th>
              </tr>
            </thead>
            <tbody></tbody>
          </table>
        </div>
      </div>
    </div>
  </div>
</div>
{% endblock %}

{% block extra_js %}
<script src="{% static 'moment/moment.js' %}"></script>
<script src="{% static 'daterangepicker/daterangepicker.js' %}"></script>
<script src="{% static 'js/echarts.min.js' %}"></script>
<script>
  (function () {
    const baseApiUrl = "{% url 'rack_report_data' %}";
    var start = moment().startOf('quarter')
    var end = moment().endOf('quarter');
    const labelMap = new Map([
      ["最近7天", "week"],
      ["最近30天", "month"],
      ["上周", "last_week"],
      ["上月", "last_month"],
      ["去年", "last_year"],
      ["本周", "this_week"],
      ["本月", "this_month"],
      ["本季度", "this_quarter"],
      ["今年", "this_year"],
      ["全部时间", "all"],
    ]);
    const defaultLabel = "本季度";

    // 全局变量用于存储当前的日期范围
    var currentAggregation = getQueryParam('aggregation') || 'week';
    var currentStart = getQueryParam('start') || start.format('YYYY-MM-DD');
    var currentEnd = getQueryParam('end') || end.format('YYYY-MM-DD');

    function cb(start, end, label) {
      // 更新全局变量
      currentStart = start.format('YYYY-MM-DD');
      currentEnd = end.format('YYYY-MM-DD');

      if (labelMap.has(label)) {
        $("#reportrange span").html(label);
      } else {
        $("#reportrange span").html(start.format("YYYY-MM-DD") + " - " + end.format("YYYY-MM-DD"));
      }
      console.log(`currentAggregation: ${currentAggregation}, currentStart: ${currentStart}, currentEnd: ${currentEnd}`)
      // 刷新数据
      refresh();
    }

    $('#reportrange').daterangepicker({
      startDate: start,
      endDate: end,
      opens: 'auto',
      locale: {
        format: "YYYY-MM-DD",
        separator: " - ",
        applyLabel: "应用",
        cancelLabel: "取消",
        fromLabel: "从",
        toLabel: "至",
        customRangeLabel: "自定义范围",
        weekLabel: "周",
        daysOfWeek: [
          "日",
          "一",
          "二",
          "三",
          "四",
          "五",
          "六"
        ],
        monthNames: [
          "1月",
          "2月",
          "3月",
          "4月",
          "5月",
          "6月",
          "7月",
          "8月",
          "9月",
          "10月",
          "11月",
          "12月"
        ],
        firstDay: 1
      },
      ranges: {
        '最近7天': [moment().subtract(6, 'days'), moment()],
        '最近30天': [moment().subtract(29, 'days'), moment()],
        '上周': [moment().subtract(1, 'week').startOf('week'), moment().subtract(1, 'week').endOf('week')],
        '上月': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')],
        '本周': [moment().startOf('week'), moment().endOf('week')],
        '本月': [moment().startOf('month'), moment().endOf('month')],
        '本季度': [moment().startOf('quarter'), moment().endOf('quarter')],
        '今年': [moment().startOf('year'), moment().endOf('year')],
        '全部时间': [-1, moment().endOf('year')]
      }
    }, cb);

    cb(start, end, defaultLabel);

    var currentRange = getQueryParam('period') || 'quarter';

    var trendChart = echarts.init(document.getElementById('rack-trend-chart'));
    var statusChart = echarts.init(document.getElementById('rack-status-chart'));
    var roomBarsChart = echarts.init(document.getElementById('room-stackedbar-chart'));

    setTimeout(function () { setActiveByValue('#aggregation-buttons .agg-btn', currentAggregation, 'data-agg'); }, 0);
    document.querySelectorAll('.agg-btn').forEach(function (btn) {
      btn.addEventListener('click', function () {
        currentAggregation = this.getAttribute('data-agg');
        setActive(this, '.agg-btn');
        refresh();
      });
    });

    var exportBtn = document.getElementById('export-report');
    if (exportBtn) {
      exportBtn.addEventListener('click', function () {
        var url = '{% url "rack_report_data" %}?aggregation=' + currentAggregation + '&period=' + currentRange;
        window.open(url, '_blank');
      });
    }

    function getQueryParam(key) { var params = new URLSearchParams(window.location.search); return params.get(key); }
    function setActive(element, selector) {
      document.querySelectorAll(selector).forEach(function (b) { b.classList.remove('active'); b.classList.remove('btn-primary'); b.classList.add('btn-default'); });
      element.classList.add('active'); element.classList.remove('btn-default'); element.classList.add('btn-primary');
    }
    function setActiveByValue(selector, value, attr) { var matched = null; document.querySelectorAll(selector).forEach(function (b) { if (b.getAttribute(attr) === value) { matched = b; } }); if (matched) { setActive(matched, selector); } }
    function renderChangeBadge(pct) { if (pct === null || pct === undefined) { return '-'; } var color = 'text-gray'; var icon = 'fa-minus'; if (pct > 0) { color = 'text-red'; icon = 'fa-arrow-up'; } else if (pct < 0) { color = 'text-green'; icon = 'fa-arrow-down'; } return '<span class="' + color + '" style="font-size:12px;"><i class="fa ' + icon + '"></i> ' + pct + '%</span>'; }
    function initPopovers() { if (window.jQuery && typeof jQuery.fn.popover === 'function') { jQuery('[data-toggle="popover"]').popover({ container: 'body' }); } }
    function refresh() {
      var apiUrl = baseApiUrl + '?aggregation=' + currentAggregation + '&start=' + currentStart + '&end=' + currentEnd;
      fetch(apiUrl).then(function (r) { return r.json(); }).then(function (data) {
        renderKpis(data.kpis);
        renderTrend(trendChart, data.trend_stats);
        renderStatus(statusChart, data.status_stats);
        renderRoomStackedBars(roomBarsChart, data.room_bar_stats);
        renderTenantStatsTable(data.tenant_stats);
      }).catch(function (err) { console.error('获取报表数据失败:', err); });
    }

    function renderKpis(kpis) {
      var totalEl = document.getElementById('rack-kpis-total');
      var totalDescEl = document.getElementById('rack-kpis-total-desc');
      var alEl = document.getElementById('rack-kpis-allocate');
      var alDescEl = document.getElementById('rack-kpis-allocate-desc');
      var deEl = document.getElementById('rack-kpis-deallocate');
      var deDescEl = document.getElementById('rack-kpis-deallocate-desc');
      if (totalEl) totalEl.textContent = (kpis && kpis.total) ? kpis.total : 0;
      if (totalDescEl) totalDescEl.innerHTML = renderChangeBadge(kpis ? kpis.total_change_percent : null) + ' {% trans "较上期" %}';
      if (alEl) alEl.textContent = (kpis && kpis.allocate) ? kpis.allocate : 0;
      if (alDescEl) alDescEl.innerHTML = renderChangeBadge(kpis ? kpis.allocate_change_percent : null) + ' {% trans "较上期" %}';
      if (deEl) deEl.textContent = (kpis && kpis.deallocate) ? kpis.deallocate : 0;
      if (deDescEl) deDescEl.innerHTML = renderChangeBadge(kpis ? kpis.deallocate_change_percent : null) + ' {% trans "较上期" %}';
    }

    function renderTrend(chart, data) {
      var option = {
        tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
        legend: { data: ['{% trans "新增" %}', '{% trans "减少" %}'] },
        grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
        xAxis: [{ type: 'category', data: data.dates, axisTick: { alignWithLabel: true } }],
        yAxis: [{ type: 'value' }],
        series: [
          { name: '{% trans "新增" %}', type: 'bar', stack: '总量', barGap: 0, data: data.rack_allocate, itemStyle: { color: '#3D9970' } },
          { name: '{% trans "减少" %}', type: 'bar', stack: '总量', data: data.rack_deallocate, itemStyle: { color: '#dd4b39' } }
        ]
      };
      chart.setOption(option);
    }

    function renderStatus(chart, data) {
      var option = {
        tooltip: { trigger: 'item', formatter: '{a} <br/>{b}: {c} ({d}%)' },
        legend: { data: data.map(function (i) { return i.name; }) },
        series: [{
          name: '{% trans "机柜状态" %}', type: 'pie', radius: ['50%', '70%'], avoidLabelOverlap: false,
          itemStyle: { borderRadius: 10, borderColor: '#fff', borderWidth: 2 },
          label: { show: false, position: 'center' }, emphasis: { label: { show: true, fontSize: 14, fontWeight: 'bold', formatter: '{b} \n\n {c}{% trans "个" %} ({d}%)' } }, labelLine: { show: false }, data: data
        }]
      };
      chart.setOption(option);
    }

    function renderRoomStackedBars(chart, data) {
      var rooms = Array.isArray(data) ? data.slice() : [];
      // 排序由后端控制（已为倒序），此处不再排序，仅根据返回顺序赋予排名
      var rankMap = {};
      (data || []).forEach(function (item, idx) { rankMap[item.room_id] = idx + 1; });
      // 高亮前10
      var topN = 10;
      var topColors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf'];

      // 装饰父节点样式与标签
      var decorated = (data || []).map(function (room) {
        var rank = rankMap[room.room_id] || null;
        var color = null;
        var borderWidth = 1;
        if (rank && rank <= topN) {
          color = topColors[rank - 1];
          borderWidth = 2;
        }
        return Object.assign({}, room, {
          itemStyle: { borderColor: '#fff', borderWidth: borderWidth, color: color },
          upperLabel: { show: true, rich: { b: { fontWeight: 'bold' } }, formatter: function (params) { var r = rankMap[params.data.room_id]; return (r ? ('TOP ' + r + ' ') : '') + params.name + '\n' + params.value + '{% trans "个" %}'; } },
          label: { show: false }
        });
      });

      var statusesSet = {};
      (rooms || []).forEach(function (r) { (r.children || []).forEach(function (c) { if ((c.value || 0) > 0) { statusesSet[c.name] = true; } }); });
      var statusNames = Object.keys(statusesSet);
      // 计算各状态总量并按降序排序，保证数量多的在左侧（先堆叠）
      var statusTotals = {};
      (rooms || []).forEach(function (r) { (r.children || []).forEach(function (c) { statusTotals[c.name] = (statusTotals[c.name] || 0) + (c.value || 0); }); });
      statusNames.sort(function (a, b) { return (statusTotals[b] || 0) - (statusTotals[a] || 0); });

      var yNames = decorated.map(function (r) { return r.name; });
      var series = statusNames.map(function (status) {
        return {
          name: status,
          type: 'bar',
          stack: 'total',
          label: {
            show: true,
            formatter: function (p) { return (p.value > 0) ? p.value : ''; }
          },
          emphasis: { focus: 'series' },
          data: decorated.map(function (r) {
            var found = (r.children || []).find(function (c) { return c.name === status; });
            return found ? found.value : 0;
          })
        };
      });

      var option = {
        tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
        legend: { type: 'scroll', orient: 'horizontal', top: 0, data: statusNames },
        grid: { left: '3%', right: '3%', bottom: 20, top: 50, containLabel: true },
        xAxis: { type: 'value' },
        yAxis: { type: 'category', data: yNames, inverse: true, axisLabel: { rotate: 90, margin: 12, align: 'center', fontWeight: 'bold' } },
        series: series
      };
      chart.setOption(option);
    }

    function renderTenantStatsTable(rows) {
      var tbody = document.querySelector('#tenant-stats-table tbody');
      if (!tbody) return;
      var data = Array.isArray(rows) ? rows.slice() : [];
      function render(d) {
        tbody.innerHTML = '';
        d.forEach(function (item) {
          var tr = document.createElement('tr');
          var icon = (item.tenant && item.tenant.icon_url) ? ('<img src="' + item.tenant.icon_url + '" alt="" style="width:20px;height:20px;border-radius:2px;"> ') : '<i class="fa fa-user-circle-o"></i> ';
          var name = (item.tenant && item.tenant.name) ? item.tenant.name : '-';
          tr.innerHTML = '<td>' + icon + name + '</td>' +
            '<td class="text-right">' + (item.total_racks || 0) + '</td>' +
            '<td class="text-right text-green">' + (item.allocated || 0) + '</td>' +
            '<td class="text-right text-red">' + (item.deallocated || 0) + '</td>' +
            '<td class="text-right">' + ((item.avg_utilization || 0).toFixed ? (item.avg_utilization.toFixed(2)) : item.avg_utilization) + '</td>' +
            '<td class="text-right">' + ((item.free_rate || 0).toFixed ? (item.free_rate.toFixed(2)) : item.free_rate) + '</td>';
          tbody.appendChild(tr);
        });
      }
      // 默认按新增倒序
      data.sort(function (a, b) { return (b.allocated || 0) - (a.allocated || 0); });
      render(data);

      // 顶部按钮排序
      var btns = document.querySelectorAll('#tenant-sort-buttons .tenant-sort-btn');
      btns.forEach(function (btn) {
        btn.addEventListener('click', function () {
          btns.forEach(function (b) { b.classList.remove('btn-primary'); b.classList.add('btn-default'); b.classList.remove('active'); });
          this.classList.add('btn-primary'); this.classList.remove('btn-default'); this.classList.add('active');
          var key = this.getAttribute('data-key');
          data.sort(function (a, b) { return (b[key] || 0) - (a[key] || 0); });
          render(data);
        });
      });
    }

    window.addEventListener('resize', function () { trendChart.resize(); statusChart.resize(); roomBarsChart.resize(); });
    initPopovers();

  })();
</script>

<script>
  (function () {
    function ensurePrintStyles() {
      if (document.getElementById('report-print-styles')) return;
      var style = document.createElement('style');
      style.id = 'report-print-styles';
      style.type = 'text/css';
      style.textContent = '@page { size: A4; margin: 10mm; }\n' +
        '@media print {\n' +
        '  .main-header, .main-sidebar, .control-sidebar, .main-footer, .navbar, .sidebar { display: none !important; }\n' +
        '  .content-wrapper, .content { margin: 0 !important; }\n' +
        '  .box { box-shadow: none !important; border: 1px solid #eee !important; }\n' +
        '  .info-box { page-break-inside: avoid; }\n' +
        '  .row { page-break-inside: avoid; }\n' +
        '  table { width: 100% !important; font-size: 12px; }\n' +
        '  #rack-trend-chart, #rack-status-chart, #room-stackedbar-chart { height: 360px !important; }\n' +
        '  #print-header { text-align: center; margin-bottom: 10px; }\n' +
        '  #print-header h1 { font-size: 24px; margin-bottom: 10px; }\n' +
        '  #print-header p { font-size: 12px; margin: 0; color: #555; }\n' +
        '}';
      document.head.appendChild(style);
    }

    function buildPrintTitle() {
      var header = document.getElementById('print-header');
      if (header && header.parentNode) header.parentNode.removeChild(header);
      var now = new Date();
      var y = now.getFullYear();
      var m = String(now.getMonth() + 1).padStart(2, '0');
      var d = String(now.getDate()).padStart(2, '0');
      var dateStr = y + '-' + m + '-' + d;
      var pageTitle = document.title.split('|')[0].trim();
      var rangeBtn = document.querySelector('.btn-group.margin-r-5 button.dropdown-toggle');
      var rangeText = rangeBtn ? rangeBtn.textContent.replace(/\s*\u25BC?$/, '').trim() : '';
      var aggActive = document.querySelector('#aggregation-buttons .agg-btn.active');
      var aggText = aggActive ? aggActive.textContent.trim() : '';
      var title = dateStr + ' - ' + pageTitle + ' - ' + (rangeText || '');
      var sub = (aggText ? ('聚合: ' + aggText) : '');
      header = document.createElement('div');
      header.id = 'print-header';
      header.innerHTML = '<h1>' + title + '</h1>' + (sub ? ('<p>' + sub + '</p>') : '');
      var content = document.querySelector('.content-wrapper .content') || document.body;
      content.insertBefore(header, content.firstChild);
      return header;
    }

    function optimizeKpiLayout() {
      var firstRow = document.querySelector('.content .row');
      if (!firstRow) return { nodes: [], reset: function () { } };
      var cols = Array.prototype.slice.call(firstRow.querySelectorAll('.info-box')).map(function (box) { return box.closest('[class*="col-"]'); }).filter(Boolean);
      var backup = cols.map(function (c) { return { node: c, style: c.getAttribute('style') }; });
      var n = cols.length || 3;
      var width = (n >= 3) ? '33.3333%' : (n === 2 ? '50%' : '100%');
      cols.forEach(function (c) { c.style.width = width; c.style.float = 'left'; });
      firstRow.style.display = 'block';
      return { nodes: cols, reset: function () { backup.forEach(function (b) { if (b.style === null) b.node.removeAttribute('style'); else b.node.setAttribute('style', b.style); }); firstRow.style.display = ''; } };
    }

    function toImagesAndPrint() {
      ensurePrintStyles();
      var headerNode = buildPrintTitle();
      var kpiReset = optimizeKpiLayout();
      var targets = Array.prototype.slice.call(document.querySelectorAll('[id$="-chart"], .echarts'));
      var backups = [];
      targets.forEach(function (el) {
        if (!window.echarts || !el) return;
        var inst = echarts.getInstanceByDom(el);
        if (!inst) return;
        try { inst.resize(); } catch (e) { }
        var dataURL = inst.getDataURL({ pixelRatio: 2, backgroundColor: '#ffffff' });
        var img = new Image();
        img.src = dataURL;
        img.style.width = (el.clientWidth || 600) + 'px';
        img.style.height = (el.clientHeight || 360) + 'px';
        backups.push({ el: el, img: img, display: el.style.display });
        el.style.display = 'none';
        el.parentNode.insertBefore(img, el.nextSibling);
      });
      function restore() { backups.forEach(function (b) { if (b.img.parentNode) { b.img.parentNode.removeChild(b.img); } b.el.style.display = b.display || ''; }); if (headerNode && headerNode.parentNode) headerNode.parentNode.removeChild(headerNode); if (kpiReset && kpiReset.reset) kpiReset.reset(); }
      var after = function () { restore(); window.removeEventListener('afterprint', after); };
      window.addEventListener('afterprint', after);
      window.print();
    }

    var btn = document.getElementById('export-report');
    if (btn) {
      btn.addEventListener('click', function (e) { e.preventDefault(); e.stopPropagation(); toImagesAndPrint(); }, true);
    }
  })();
</script>
{% endblock %}